#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/iio/imu/icm42686.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/jiffies.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/time64.h>
#include <linux/timer.h>
#include <linux/rtc.h>
#include <linux/timex.h>
#include <linux/ioctl.h>
#include <linux/spinlock.h> 
#include <linux/timekeeping.h>
#include <media/v4l2-subdev.h>
// #include "icm42686.h"

#define IMX586_REG_CTRL_MODE 0x0100
#define IMX586_MODE_SW_STANDBY 0x0
#define IMX586_MODE_STREAMING BIT(0)
#define IMX586_REG_VALUE_08BIT 1
#define IMX586_REG_VALUE_16BIT 2
#define IMX586_REG_VALUE_24BIT 3
#define TIMEROPEN 5
#define TIMERCLOSE 1
#define TIMEROFFSET 3
#define SYNCINFO_MAXCOUNT 2000
#define REG_NULL 0xFFFF
#define IMU_COUT_MAX 40

struct timer_list m_timer;    //定时器
atomic_t hrtime_v = ATOMIC_INIT(0);
unsigned int last_frame_sequence[2]={0};        
unsigned int last_app_frame_sequence[2]={0};        

typedef struct  camera_info {
    unsigned long long exp_timestamp_us; //同步时间戳
    unsigned short exp_value;//线性曝光值,HDR长曝光值
    unsigned short exp_short_value;//HDR短曝光值
    unsigned short again_value;//线性模拟增益 //HDR长曝光模拟增益
    unsigned short again_short_value;//HDR短曝光模拟增益
    unsigned short dgain_value;//线性数字增益,HDR短曝光数字增
    unsigned short dgain_short_value;//HDR短曝光模拟增益
    unsigned char  sync_info;
} APP_FRAME_SERSON_SYNC_INFO;

// 应用查询同步信息数据结构
typedef struct app_frame_imu_sync_info {
    unsigned char type;  // 查询使用 0 下视 1前视
    unsigned char sync;  // 0 没有同步  1 同步下视IMU  2同步前视IMU
    int framemode;       // 0 视频帧 1 拍照帧
    unsigned int frame_sequence;                           // 帧号
    unsigned long long frame_timestamp;                    // 相对时间戳
    unsigned long long frame_systimestamp;                 // 系统时间戳
    unsigned long long frame_systimestamp_us;                 // 系统时间戳
    struct icm42686_data imu_frontdata[IMU_COUT_MAX];   // 前视MU数据值
    struct icm42686_data imu_bottomdata[IMU_COUT_MAX];  // 后视IMU数据值
    int imu_count;                                         // IMU个数
    int snap_count;                                        // 拍照触发次数
    struct  camera_info  serson_frontdata;
    struct  camera_info  serson_bottomdata;
    long int time_offset ;
} APP_FRAME_IMU_SYNC_INFO;

#define IOCTL_BASE 'S'
#define IMX586_SYNC_CMD \
    _IOWR(IOCTL_BASE, 0, int)  // 读命令, 带参char*, 自定义0为命令编号不可重复

#define IMX586_IMU_TIMESTAMP_QUERY_CMD \
    _IOWR(IOCTL_BASE, 1, APP_FRAME_IMU_SYNC_INFO)

#define IMX586_SANP_CMD \
    _IOWR(IOCTL_BASE, 2, int)  // 命令, 带参char*, 自定义2为命令编号不可重复

#define IMX586_SYNC_HDR_CMD \
    _IOWR(IOCTL_BASE, 3, int)  // 读命令, 带参char*, 自定义3为命令编号不可重复

typedef struct frame_systime_sync_info {
    APP_FRAME_SERSON_SYNC_INFO front_sensor_data;
    APP_FRAME_SERSON_SYNC_INFO bottom_sensor_data;
    unsigned long long   sys_timestamp;
    unsigned long long  timestamp;
    struct list_head list;
} FRAME_SERSON_SYNC_INFO;

unsigned long long sys_time_ms;

// 链表的头结点, (无数据)
extern struct list_head m_frame_imu_synclist;
extern atomic_t m_frame_imu_synclist_count ;
struct rtc_time m_syc_tm; 

FRAME_IMU_SYNC_INFO m_imu_syncinfo;
APP_FRAME_IMU_SYNC_INFO app_frame_imu_syncinfo;

int m_imu_syncinfo_count = -1;     // IMU获取次数
int m_frame_triger_sequence = 0;  // IMU获取次数
int m_snap_flag = 0;
int m_snap_count = 0;
int m_first = 0;
int m_hdr_mode = 0;
int value = 2000;
unsigned long long m_tmp_ms;
unsigned long long  m_sys_time_ms  = 0;
unsigned int m_work_count = 0;
unsigned long long m_sys_time = 0;
spinlock_t m_spinlock ;      
struct work_struct exp_work;
atomic_t m_frame_sersoninfo_synclist_count = ATOMIC_INIT(0);
struct list_head m_frame_sersoninfo_synclist;
unsigned long long timer_count = 0;
struct hrtimer hrtimer_sync_timer;
ktime_t m_kt;
ktime_t m_kt_closer;
unsigned long long last_sys_time_ms[2] = {0};
unsigned long long last_time_ms[2] = {0};

extern struct i2c_client* imx586_i2c_client;
extern int imx586_write_reg(struct i2c_client* client,
                             u16 reg,
                             u32 len,
                             u32 val);

extern int imx586_read_reg(struct i2c_client* client,
                            u16 reg,
                            unsigned int len,
                            u32* val);

struct regval {
    u16 addr;
    u8 val;
};

static const struct regval sc230ai_linear_sync_10_1920x1080_regs[] = {
    {REG_NULL, 0x00},
};

static const struct regval sc230ai_hdr_10_1920x1080_regs[] = {
    {0x0103,0x01},
    {0x37f9,0x24},
	{REG_NULL, 0x00},
};

static int imx586_write_array(struct i2c_client* client,
                               const struct regval* regs) {
    u32 i;
    int ret = 0;
    if(client == NULL )return -1;
    for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
        ret = imx586_write_reg(client, regs[i].addr, IMX586_REG_VALUE_08BIT,
                                    regs[i].val);

    return ret;
}

int hrtimer_add_imu(void) 
{   
    struct timespec64 systime;

    if (icm42686dev_iio != NULL) {
        ktime_get_real_ts64(&systime );        
        icm42686_get_data_front(NULL, NULL);
    }

    return 0;
}

/*通过格林威治时间，计算本地时间*/
int GMT_toLocalTime(unsigned long gmt_time,unsigned int* year,unsigned int* month,
                    unsigned int* day,unsigned int* hour,unsigned int* minute,unsigned int* sec)
{
	int TIME_ZONE	= 8;
	unsigned long gmtTime = gmt_time + TIME_ZONE * 60 * 60;
	int leap_years = 0;
	int month_days[] = {31, 28, 31,30,31, 30,31,31, 30,31,30,31};
	int i =0;
	int days;
			
	*sec = (int)(gmtTime%60);//秒钟数
	gmtTime = gmtTime/60;//总共有多少分钟
    
	*minute = (int)(gmtTime%60);
	gmtTime = gmtTime/60;//总共有多少小时
	
	*hour = (int)(gmtTime%24);
	gmtTime = gmtTime/24;//总共有多少天
	
	//去掉小时分钟秒钟后，转换成从公元元年开始到现在的天数 
	//不包括今天
	gmtTime += 719162;

	*year = (int)(gmtTime / 365);
	days = (int)(gmtTime % 365);

	while(1) {
		//总共有多少个闰年，天数要相应的减去这些天数
		leap_years = (*year)/4 - (*year)/100; //计算普通闰年
		leap_years += (*year)/400; //加上世纪闰年

		if(days < leap_years) {
			days+=365;
			(*year)--;
		}
        else break;
	}

	days -= leap_years;
	(*year)++;
	days++;
	//计算今年总共度过了多少秒
	if(((*year)%4 == 0 && (*year) % 100!=0) || (*year)%400==0) 
        month_days[1] = 29;//今年是闰年,修改二月份为29天

	*month = 1;

	for (i = 0; i < 12; i++) {
		if(days <= month_days[i]) {
			break;
		}
		else {
			days -=month_days[i];
			(*month)++; 
		}
	}
	*day =days; 

	return 0;
}
/*格林威治时间就是1970年01月01日00时00分00秒起至现在的总秒数*/

int hrtimer_frame_imu_query_synclist(APP_FRAME_IMU_SYNC_INFO* app_syncinfo) {
    struct list_head *pos, *node,*pos_tmp;
    FRAME_IMU_SYNC_INFO* tmp_syncinfo = NULL;
    FRAME_SERSON_SYNC_INFO *tmp_sersoninfo =NULL;
    
    int diff = 0;
    int max_diff = 40, found = 0;
    unsigned long long sys_time_ms = 0;
    unsigned long long time_ms = 0, tmp_time_us;
    unsigned long long app_time_ms = 0;
    
    unsigned long long comp_time_ms = 0, offset_time = 0;
    int index = 0, comp_count = 0;
    struct timespec64 systime;

    if(  app_syncinfo == NULL) 
        return 0;
    app_syncinfo->imu_count  = 0;    
    ktime_get_real_ts64(&(systime)); 

    sys_time_ms =  (unsigned long long )systime.tv_sec * 1000 + systime.tv_nsec/1000000;
    // printk("ihrtimer_frame_imu_query_synclist(\n");

    //寻找IMU
try_comp:
    if (app_syncinfo == NULL) 
        return 0;
    if(list_empty(&m_frame_imu_synclist))
      return 0;

    list_for_each_safe(pos, node, &m_frame_imu_synclist) {
        tmp_syncinfo = list_entry(pos, FRAME_IMU_SYNC_INFO, list);
        if( tmp_syncinfo == NULL) 
            return 0;

        time_ms   = last_time_ms[app_syncinfo->type] ;
        //判断当前图像帧时间,能否找到对应时间的IMU
        comp_time_ms = tmp_syncinfo->app_frame_imu_one_synclist.frame_timestamp - offset_time;

        if (app_syncinfo->frame_timestamp - comp_time_ms == 0) {
            if(app_syncinfo->frame_sequence < 20) {
                last_app_frame_sequence[app_syncinfo->type] =   app_syncinfo->frame_sequence;     
                last_time_ms[app_syncinfo->type ]  =      app_syncinfo->frame_timestamp;   
                goto ret;
            }
            //取当前帧时间与上一帧图像时间间的IMU
            app_time_ms  =  last_time_ms[app_syncinfo->type]   =   app_syncinfo->frame_systimestamp;   

            diff =   app_syncinfo->frame_timestamp -  last_time_ms[app_syncinfo->type ];
            //跳帧判断
            if(diff >= 45) {
                max_diff = 33;
                printk("cam id %d  last frame %llu loss frame :%llu \n",app_syncinfo->type, 
                        last_time_ms[app_syncinfo->type ],app_syncinfo->frame_timestamp);
            }

            /*if(app_syncinfo->type == 1 ) { 
                printk("f time %llu imu time%llu last imu time%llu\n",app_syncinfo->frame_timestamp ,
                        tmp_syncinfo->app_frame_imu_one_synclist.frame_timestamp,last_time_ms[app_syncinfo->type ] );
            }*/

            diff  = 0;
            tmp_time_us = app_time_ms *1000;
            pos_tmp = pos;
            //寻找当前曝光图像时间
            for(index = 0 ; index < max_diff  ;++index) {
                pos_tmp  = pos_tmp->prev;
                if(pos_tmp == &m_frame_imu_synclist) {
                    //  printk("imu_list is head\n");
                    goto ret;
                }
                tmp_syncinfo = list_entry(pos_tmp, FRAME_IMU_SYNC_INFO, list);
                if(tmp_syncinfo == NULL)
                    goto ret;
                // printk("diff : %llu %llu\n",tmp_syncinfo->app_frame_imu_one_synclist.imu_time_us,tmp_time_us);
                if(tmp_syncinfo->app_frame_imu_one_synclist.imu_time_us< tmp_time_us) {
                    pos  =  pos_tmp->next;
                    if(pos == NULL)
                        goto ret;
                    found ++;
                    break;
                }
            }

            tmp_time_us =  app_syncinfo->frame_timestamp  *1000;

            if (found  != 0) {
                pos_tmp = pos;    

                //将大于当前曝光图像时间, 小于图像接收中断,IMU的时间戳保存
                for (index = 0 ; index < max_diff  ;++index) {
                    tmp_syncinfo = list_entry(pos_tmp, FRAME_IMU_SYNC_INFO, list);
                    if(tmp_syncinfo == NULL)
                        goto ret;

                    if (tmp_syncinfo->app_frame_imu_one_synclist.imu_time_us <= tmp_time_us) {
                        memcpy(&app_syncinfo->imu_bottomdata[diff],
                                    &tmp_syncinfo->app_frame_imu_one_synclist.imu_bottomdata,
                                    sizeof(tmp_syncinfo->app_frame_imu_one_synclist.imu_bottomdata));
                        memcpy(&app_syncinfo->imu_frontdata[diff],
                                    &tmp_syncinfo->app_frame_imu_one_synclist.imu_frontdata,
                                    sizeof(tmp_syncinfo->app_frame_imu_one_synclist.imu_bottomdata));

                        if(diff == 0){
                            app_syncinfo->frame_systimestamp = tmp_syncinfo->app_frame_imu_one_synclist.frame_systimestamp;
                            app_syncinfo->frame_timestamp =  app_syncinfo->frame_timestamp;   
                        }
                        diff++;
                    }else {
                        break;
                    }
                    pos_tmp  = pos_tmp->next;
                }
            }

            last_app_frame_sequence[app_syncinfo->type] =   app_syncinfo->frame_sequence;     
            last_time_ms[app_syncinfo->type ]  =      app_syncinfo->frame_timestamp;   

            // printk("diff : %llu\n",diff);
            // 拷贝同步信息
            app_syncinfo->sync =  app_syncinfo->type +1 ;
            app_syncinfo->frame_sequence = app_syncinfo->frame_sequence;
            app_syncinfo->imu_count = diff;

            last_sys_time_ms[app_syncinfo->type ] =  app_syncinfo->frame_systimestamp ;
            app_syncinfo->framemode = 0;

            goto ret;
            // spin_unlock_irqrestore(&my_lock, flags);
            // printk("imu sync ok %ld\n",app_syncinfo->frame_timestamp );
            return 1;
        }
    }

    if(app_syncinfo->frame_timestamp < comp_time_ms  && tmp_syncinfo != NULL) {
        // printk("fix ime %llu  try aragin \n", app_syncinfo->frame_timestamp);
        offset_time ++;
        comp_count ++;
        if(comp_count <=2)
            goto try_comp;
    }

    app_syncinfo->frame_systimestamp = sys_time_ms;
    app_syncinfo->sync = 0;
    //printk("imu sync fail %llu last time :%llu\n", app_syncinfo->frame_timestamp,comp_time_ms);
    //printk("imu sync exp %llu last time :%llu\n", app_syncinfo->frame_timestamp,comp_time_ms);
    //寻找帧曝光时间,当前帧结束时间减去1帧内时间,该时间点读取的曝光信息认为当前帧曝光时间

 ret:
    comp_time_ms = app_syncinfo->frame_timestamp - 66;
    //printk("imu sync exp %llu last time :%llu\n", app_syncinfo->frame_timestamp,comp_time_ms);
    if(list_empty(&m_frame_sersoninfo_synclist))
        return 0;

    list_for_each_safe(pos, node, &m_frame_sersoninfo_synclist) {
        tmp_sersoninfo= list_entry(pos, FRAME_SERSON_SYNC_INFO, list);
        if( tmp_sersoninfo == NULL)
            break;

        if(comp_time_ms <= tmp_sersoninfo->timestamp && 
                tmp_sersoninfo->timestamp <=  app_syncinfo->frame_timestamp ) { 
            app_syncinfo->serson_frontdata.exp_value         = tmp_sersoninfo-> front_sensor_data.exp_value;
            app_syncinfo->serson_frontdata.exp_short_value   = tmp_sersoninfo->front_sensor_data.exp_short_value;
            app_syncinfo->serson_frontdata.again_value       = tmp_sersoninfo->front_sensor_data.again_value;
            app_syncinfo->serson_frontdata.again_short_value = tmp_sersoninfo->front_sensor_data.again_short_value;
            app_syncinfo->serson_frontdata.dgain_value       = tmp_sersoninfo->front_sensor_data.dgain_value;
            app_syncinfo->serson_frontdata.exp_timestamp_us  = tmp_sersoninfo->sys_timestamp;
            app_syncinfo->serson_frontdata.sync_info         = 1;
            goto ret1;
        }
    }
    // printk("imu sync minx exp %llu max exp time :%llu\n", comp_time_ms ,app_syncinfo->frame_timestamp);
    app_syncinfo->serson_frontdata.sync_info= 0;

ret1:
    index = 0;
    if (atomic_read(&m_frame_imu_synclist_count) > SYNCINFO_MAXCOUNT) {
       // printk("syncinfo is full \n");
        if(list_empty(&m_frame_imu_synclist))
            return 0;

        list_for_each_safe(pos, node, &m_frame_imu_synclist) {
            if (index >= 33)
                break;
            ++index;
            tmp_syncinfo = list_entry(pos, FRAME_IMU_SYNC_INFO, list);
            atomic_dec(&m_frame_imu_synclist_count);
            if( tmp_syncinfo == NULL)
                continue;
            list_del(&(tmp_syncinfo->list));
            kfree(tmp_syncinfo);
            tmp_syncinfo = NULL;
            
            // printk("<0>student %d name: %s is being
            // deleted.\n",tmp_student->num,tmp_student->name);
        }
    }
    
    index = 0;
    if (atomic_read(&m_frame_sersoninfo_synclist_count) > 200) {
        // printk("syncinfo is full \n");?
        if(list_empty(&m_frame_sersoninfo_synclist))
            return 0;

        list_for_each_safe(pos, node, &m_frame_sersoninfo_synclist) {
            if (index >= 5)
                break;

            ++index;
            tmp_sersoninfo = list_entry(pos, FRAME_SERSON_SYNC_INFO, list);
            atomic_dec(&m_frame_sersoninfo_synclist_count);
            if (tmp_sersoninfo == NULL)
                continue;

            list_del(&(tmp_sersoninfo->list));
            kfree(tmp_sersoninfo);
            tmp_sersoninfo = NULL;

            // printk("<0>student %d name: %s is being
            // deleted.\n",tmp_student->num,tmp_student->name);
        }
    }

    return 0;
}

static enum hrtimer_restart hrtimer_sync_timer_triger(struct hrtimer* timer) 
{
    struct timespec64 systime;

    m_tmp_ms = ktime_to_ms(ktime_get());
    ktime_get_real_ts64(&(systime)); 

    m_sys_time_ms =  (unsigned long long )systime.tv_sec * 1000 + systime.tv_nsec/1000000;
    hrtimer_add_imu();

    if(++m_work_count == 3) {
        schedule_work(&exp_work);
        m_work_count  = 0;
    } 
   
    hrtimer_forward_now(timer, m_kt);  // hrtimer_forward(timer, now, tick_period)

    return HRTIMER_RESTART;
}

static void work_queue_exp(struct work_struct *arg) {  
    int val[5] = {0}; 
    int val1 = 0;
    FRAME_SERSON_SYNC_INFO *sersoninfo;
    struct timespec64 systime;
    int exp_val = 0, exp_val_short = 0, again_value ,dgain_value;

    ktime_get_real_ts64(&(systime)); 
    sersoninfo =(FRAME_SERSON_SYNC_INFO*)kmalloc(sizeof(FRAME_SERSON_SYNC_INFO), GFP_KERNEL);
    if (sersoninfo  == NULL) {
        printk("sersoninfo malloc fail \n");
        return ;
    }    

    sersoninfo->sys_timestamp =  (unsigned long long )systime.tv_sec * 1000000 + systime.tv_nsec;
    sersoninfo->timestamp  = ktime_to_ms(ktime_get());
   //  printk("add exp time  %llu \n", sersoninfo->timestamp );
    imx586_read_reg(imx586_i2c_client, 0x3e00, 1, &val[0]);  
    imx586_read_reg(imx586_i2c_client, 0x3e01, 1, &val[1]);  
    imx586_read_reg(imx586_i2c_client, 0x3e02 ,1,  &val[2]);  

    exp_val  = (val[0]  & 0x0f) << 12 |  (val[1]  & 0xff ) << 4   |  (val[2]  & 0xf0 >>4 );

    imx586_read_reg(imx586_i2c_client, 0x3e22 ,1, &val[0]);  
    imx586_read_reg(imx586_i2c_client, 0x3e04, 1, &val[1]);  
    imx586_read_reg(imx586_i2c_client, 0x3e05 ,1,  &val[2]);  

    exp_val_short = (val[0]  & 0x0f) << 12 |  (val[1]  & 0xff ) << 4   |  (val[2]  & 0xf0 >>4 );

    imx586_read_reg(imx586_i2c_client, 0x3e09, 1, &val1);  
    
    again_value = val1;

    imx586_read_reg(imx586_i2c_client, 0x3e06, 1, &val[0]);  
    
    dgain_value = val[0];

    // printk("f exp info time  %llu exp :%x exp short %x again %x dgain %x",time_ms,exp_val,exp_val_short ,again_val,//dgain_val);
    sersoninfo-> front_sensor_data.exp_value = exp_val ;
    sersoninfo-> front_sensor_data.exp_short_value = exp_val_short ;
    sersoninfo-> front_sensor_data.again_value = again_value ;
    sersoninfo-> front_sensor_data.dgain_value = dgain_value ;

    list_add_tail(&sersoninfo->list, &m_frame_sersoninfo_synclist);
    atomic_inc(&m_frame_sersoninfo_synclist_count);
}

long hrtimer_sync_ioctl(struct file* f, unsigned int cmd, unsigned long arg) 
{
    int erro = 0;
    int ret, val;
    void __user* ptr;
    ptr = (void __user*)arg;
    
    //   printk("hrtimer_sync_ioctl cmd %x\n", cmd);
    switch (cmd) {
        case IMX586_SYNC_CMD:
            ret = imx586_write_reg(
                imx586_i2c_client, IMX586_REG_CTRL_MODE,
                IMX586_REG_VALUE_08BIT, IMX586_MODE_SW_STANDBY);
            if (ret < 0) {
                printk("hrtimer_sync sc230ai sw standby fail\n");
                erro += 1;
                if (erro >= 3) {
                    return -1;
                }
            }

            imx586_read_reg(imx586_i2c_client, 0x320c, 1, &val);

            printk("0x320c:0x%x\n", val);

            imx586_read_reg(imx586_i2c_client, 0x320d, 1, &val);

            printk("0x320d:0x%x\n", val);
            m_frame_triger_sequence = 0;
            m_kt_closer = ktime_set(0, TIMERCLOSE * 1000000);
            m_kt = ktime_set(0, 4 * 1000000);
            hrtimer_start(&hrtimer_sync_timer, m_kt,  HRTIMER_MODE_ABS);

            if(m_hdr_mode == 1){
                 imx586_write_array(imx586_i2c_client,
                                 sc230ai_hdr_10_1920x1080_regs);   
                 printk("hdr mode ok\n");               
            } else {
                imx586_write_array(imx586_i2c_client,
                            sc230ai_linear_sync_10_1920x1080_regs);
            }
          
            // printk("0x3222:0x%x\n", val);
            printk("master fifo mode ok v1.0\n");
            printk("hrtimer_sync_start\n");
            
            break;

        case IMX586_SANP_CMD:
            m_snap_flag = 1;
            m_snap_count = arg;
            printk("recv snap... :%d\n", m_snap_count);
            break;

        case IMX586_IMU_TIMESTAMP_QUERY_CMD:
            spin_lock( &m_spinlock);
            /* 读取应用层写入的数据 */
            memset(&app_frame_imu_syncinfo, 0, sizeof(app_frame_imu_syncinfo));

            if (0 != copy_from_user((void*)&app_frame_imu_syncinfo, 
                                    ptr,
                                    sizeof(app_frame_imu_syncinfo))) {
                printk("[KERNEL]:ERROR: %s write error!\n\n", __FUNCTION__);
                spin_unlock( &m_spinlock );  

                return -1;
            }
            //  printk("hrtimer_sync time type :%d fmdid:%u  %lu size:%d
            //  \n",app_frame_imu_syncinfo.type,
            //  app_frame_imu_syncinfo.frame_sequence
            //  ,app_frame_imu_syncinfo.frame_timestamp
            //  ,sizeof(app_frame_imu_syncinfo)  );
            GMT_toLocalTime(app_frame_imu_syncinfo.frame_systimestamp,
                                &m_syc_tm.tm_year,&m_syc_tm.tm_mon,&m_syc_tm.tm_mday,
                                &m_syc_tm.tm_hour,&m_syc_tm.tm_min,&m_syc_tm.tm_sec);

            hrtimer_frame_imu_query_synclist(&app_frame_imu_syncinfo);
            if (0 != copy_to_user(ptr, (void*)&app_frame_imu_syncinfo,
                                  sizeof(app_frame_imu_syncinfo))) {
                printk("[KERNEL]:ERROR: %s write error!\n\n", __FUNCTION__);
                spin_unlock( &m_spinlock);  

                return -1;
            }

            spin_unlock( &m_spinlock);  
            break;

        case IMX586_SYNC_HDR_CMD:            
                if(*(int *)ptr== 1) {
                    m_hdr_mode = 1;
                }
                else {
                    m_hdr_mode = 0;
                }
                break;      
    }

    return 0;
}

ssize_t hrtimer_sync_write(struct file* f,
                           const char __user* buf,
                           size_t t,
                           loff_t* len) {
    int erro = 0;
    int ret;
    int cmd = IMX586_SYNC_CMD;
    printk("hrtimer Debug buf:%x size:%ld\n", *buf, t);

    if (*buf == '0') {
        printk("hrtimer_start\n");
        printk("hrtimer_sync_ioctl cmd %d\n", cmd);
        switch (cmd) {
            case IMX586_SYNC_CMD:
                ret = imx586_write_reg(imx586_i2c_client, IMX586_REG_CTRL_MODE,
                                            IMX586_REG_VALUE_08BIT, IMX586_MODE_SW_STANDBY);
                if (ret < 0) {
                    printk("hrtimer_sync sc230ai sw standby fail\n");
                    erro += 1;
                    if (erro >= 3) {
                        return -1;
                    }
                }

                imx586_write_array(imx586_i2c_client,
                                        sc230ai_linear_sync_10_1920x1080_regs);

                m_frame_triger_sequence = 0;
                printk("slave mode ok\n");
                printk("hrtimer_sync_start\n");
                m_kt_closer = ktime_set(0, TIMERCLOSE * 1000000);
                m_kt = ktime_set(0, TIMEROPEN * 1000000);
                hrtimer_start(&hrtimer_sync_timer, m_kt, HRTIMER_MODE_REL_PINNED);
                break;
        }
    }
    else if (*buf == '1') {
        printk("hrtimer_cancel\n");
        hrtimer_cancel(&hrtimer_sync_timer);
    }

    return t;
}
static const struct file_operations hrtimer_sync_fops = {
    .owner = THIS_MODULE,
    .write = hrtimer_sync_write,
    .unlocked_ioctl = hrtimer_sync_ioctl,
};

struct miscdevice hrtimer_sync_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "hrtimer_sync",
    .fops = &hrtimer_sync_fops,
};

static int __init hrtimer_sync_init(void) {
    int ret=0;
    printk("hrtimer_sync_init \n");

    if (imx586_i2c_client == NULL) {
        printk("hrtimer_sync sc230ai front i2c  no init\n");
        return -1;
        ret++;
    }
    else {
        printk("hrtimer_sync sc230ai front i2c  init ok\n");
    }

    if(ret >= 1) {
        printk("hrtimer_sync sc230ai  sync init fail\n");
        return -1;
    }
     
    INIT_LIST_HEAD(&m_frame_imu_synclist);
    INIT_LIST_HEAD(&m_frame_sersoninfo_synclist);

    ret = misc_register(&hrtimer_sync_dev);

    hrtimer_init(&hrtimer_sync_timer,CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
    hrtimer_sync_timer.function = hrtimer_sync_timer_triger;

    INIT_WORK(&exp_work, & work_queue_exp);
    spin_lock_init( &m_spinlock ); 

    return 0;
}

static void __exit hrtimer_sync_exit(void) {
    misc_deregister(&hrtimer_sync_dev);
}

module_init(hrtimer_sync_init);
module_exit(hrtimer_sync_exit);
MODULE_AUTHOR("hrtimer<hrtimer@hrtimer.cc>");
MODULE_LICENSE("GPL");